Java25的新特性


                                                                                                                                                <p>&gt;Java语言特性系列</p> 

本文主要讲述一下Java25的新特性

版本号

openjdk version "25" 2025-09-16
OpenJDK Runtime Environment (build 25+36-3489)
OpenJDK 64-Bit Server VM (build 25+36-3489, mixed mode, sharing)

>从version信息可以看出是build 25+36

特性列表

JEP 470: PEM Encodings of Cryptographic Objects (Preview)

本特性为Java平台引入了一套简洁、易用且线程安全的API(Preview版本),用于在 PEM(Privacy-Enhanced Mail)文本与各类密码学对象(密钥、证书、CRL 等)之间进行双向转换,解决开发者长期需要手写解析/格式化逻辑的痛点。

  • DEREncodable 标记接口 统一标识可参与 PEM 编解码的已有类型: AsymmetricKey、X509Certificate、X509CRL、KeyPair、EncryptedPrivateKeyInfo、PKCS8EncodedKeySpec、X509EncodedKeySpec 以及新引入的 PEMRecord。

  • PEMEncoder / PEMDecoder 不可变、可复用、线程安全。 支持直接编解码字符串或字节流,提供 encode(DerEncodable) / decode(String/InputStream) 等便捷方法。 通过 withEncryption(char[] password) / withDecryption(…) 一键加解密私钥;默认算法可在安全属性文件中配置(当前为 PBEWithHmacSHA256AndAES_128)。 通过 withFactory(Provider) 可指定特定加密提供者。

  • PEMRecord 记录类 用于处理平台暂无对应 API 的 PEM 类型(如 PKCS#10 请求)或需要保留 PEM 首部前导数据的场景。

  • EncryptedPrivateKeyInfo 增强 新增静态工厂方法 encryptKey(…) 与实例方法 getKey(…),方便先加密成 EncryptedPrivateKeyInfo 再编码为 PEM,或解码后直接解密拿到 PrivateKey。

使用示例

public class PEMEncoding {
    public static void main() throws NoSuchAlgorithmException {
        // Enable preview features: --enable-preview --release 25

        // 1. Generate an EC key pair
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // 2. Encode public key to PEM
        String publicKeyPEM = PEMEncoder.of()
                .encodeToString(keyPair.getPublic());
        System.out.println("Public Key PEM:\n" + publicKeyPEM);

        // 3. Encode a private key to encrypted PEM
        char[] password = "secret".toCharArray();
        String privateKeyPEM = PEMEncoder.of()
                .withEncryption(password)
                .encodeToString(keyPair.getPrivate());
        System.out.println("Encrypted Private Key PEM:\n" + privateKeyPEM);

        // 4. Decode a public key
        PublicKey decodedPubKey = PEMDecoder.of()
                .decode(publicKeyPEM, PublicKey.class);
        System.out.println("Decoded Public Key Algo: " + decodedPubKey.getAlgorithm());

        // 5. Decode encrypted private key
        PrivateKey decodedPrivateKey = PEMDecoder.of()
                .withDecryption(password)
                .decode(privateKeyPEM, PrivateKey.class);
        System.out.println("Decoded Private Key Algo: " + decodedPrivateKey.getAlgorithm());
    }
}

编译及运行

javac --release 25 --enable-preview PEMEncoding.java
java  --enable-preview PEMEncoding

JEP 502: Stable Values (Preview)

本特性引入了一种名为 Stable Values(稳定值) 的 API,用于支持延迟初始化的不可变数据持有者对象。这一特性在 JDK 25 中以预览功能形式提供,旨在提升 Java 应用的启动性能与并发安全性,同时保留 final 字段的优化能力(如常量折叠)。 Stable Values填补了final字段与可变字段之间的空白,在保持不可变性和线程安全的同时,支持按需初始化,特别适用于启动时需要延迟加载资源的大型应用场景。

使用示例如下:

class OrderController {

    // OLD:
    // private Logger logger = null;

    // NEW:
    private final StableValue<logger> logger = StableValue.of();

    Logger getLogger() {
        return logger.orElseSet(() -&gt; Logger.create(OrderController.class));
    }

    void submitOrder(User user, List<product> products) {
        getLogger().info("order started");
        ...
        getLogger().info("order submitted");
    }

}

由于是预览版本,所以需要--enable-preview启用

javac --release 25 --enable-preview Main.java
java --enable-preview Main

JEP 503: Remove the 32-bit x86 Port

在JDK21的JEP 449: Deprecate the Windows 32-bit x86 Port for Removal已经废弃了对Windows 32位 x86的移植 在JDK24的JEP 479: Remove the Windows 32-bit x86 Port删除了相关源代码、移除了对windows 32位相关构建支持 在JDK24的JEP 501: Deprecate the 32-bit x86 Port for Removal废弃了对32位x86的移植,但是可以通过--enable-deprecated-ports=yes来启用构建 在JDK25Z则删除了相关源代码、移除了相关构建支持

JEP 505: Structured Concurrency (Fifth Preview)

>JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator >JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator >JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview >JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview >JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview >JDK24的JEP 499: Structured Concurrency (Fourth Preview)作为第四次preview >JDK25作为第五次preview

使用示例如下:

Response handle() throws InterruptedException {

    try (var scope = StructuredTaskScope.open()) {

        Subtask<string> user = scope.fork(() -&gt; findUser());
        Subtask<integer> order = scope.fork(() -&gt; fetchOrder());

        scope.join();   // Join subtasks, propagating exceptions

        // Both subtasks have succeeded, so compose their results
        return new Response(user.get(), order.get());

    }

}

JEP 506: Scoped Values

JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview JDK24的JEP 487: Scoped Values (Fourth Preview)作为第四次preview,与JDK23不同的是callWhere以及runWhere方法从ScopedValue类中移除,可以使用ScopedValue.where()再链式调用run(Runnable)或者call(Callable)

JDK25作为第五次preview,有个改动就是ScopedValue.orElse方法不再接受null作为参数

示例:

class Framework {

    private static final ScopedValue<frameworkcontext> CONTEXT
                        = ScopedValue.newInstance();    // (1)

    void serve(Request request, Response response) {
        var context = createContext(request);
        where(CONTEXT, context)                         // (2)
                   .run(() -&gt; Application.handle(request, response));
    }

    public PersistedObject readKey(String key) {
        var context = CONTEXT.get();                    // (3)
        var db = getDBConnection(context);
        db.readKey(key);
    }

}

>在 (1) 中,框架声明了一个作用域值,而不是一个thread local变量。在 (2),serve方法调用where … run而不是thread local的set方法。run方法提供了数据的单向共享serve方法到readKey方法。(3) 读取的值是由Framework.serve的时候写入的。

JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)

JDK19的JEP 405: Record Patterns (Preview)将Record的模式匹配作为第一次preview JDK20的JEP 432: Record Patterns (Second Preview)作为Record模式匹配第二次preview JDK21的JEP 440: Record Patterns则将Record模式匹配正式发布 JDK23的JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)将原始类型的匹配作为第一次preview JDK24的JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)作为第二次preview JDK25作为第三次preview

record Point(int x, int y) {}

// As of Java 21
static void printSum(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}
// As of Java 21
static void printUpperLeftColoredPoint(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint ul, ColoredPoint lr)) {
         System.out.println(ul.c());
    }
}

static void printColorOfUpperLeftPoint(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point p, Color c),
                               ColoredPoint lr)) {
        System.out.println(c);
    }
}

>但是这个只是支持Record类型

在JDK14JEP 305: Pattern Matching for instanceof (Preview)作为preview 在JDK15JEP 375: Pattern Matching for instanceof (Second Preview)作为第二轮的preview 在JDK16JEP 394: Pattern Matching for instanceof转正 JDK17引入JEP 406: Pattern Matching for switch (Preview) JDK18的JEP 420: Pattern Matching for switch (Second Preview)则作为第二轮preview JDK19的JEP 427: Pattern Matching for switch (Third Preview)作为第三轮preview JDK20的JEP 433: Pattern Matching for switch (Fourth Preview)作为第四轮preview JDK21的JEP 441: Pattern Matching for switch将Pattern Matching for switch作为正式版本发布,示例如下

// Prior to Java 21
static String formatter(Object obj) {
    String formatted = "unknown";
    if (obj instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (obj instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (obj instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (obj instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;
}

// As of Java 21
static String formatterPatternSwitch(Object obj) {
    return switch (obj) {
        case Integer i -&gt; String.format("int %d", i);
        case Long l    -&gt; String.format("long %d", l);
        case Double d  -&gt; String.format("double %f", d);
        case String s  -&gt; String.format("String %s", s);
        default        -&gt; obj.toString();
    };
}

// As of Java 21
static void testFooBarNew(String s) {
    switch (s) {
        case null         -&gt; System.out.println("Oops");
        case "Foo", "Bar" -&gt; System.out.println("Great");
        default           -&gt; System.out.println("Ok");
    }
}

// As of Java 21
static void testStringEnhanced(String response) {
    switch (response) {
        case null -&gt; { }
        case "y", "Y" -&gt; {
            System.out.println("You got it");
        }
        case "n", "N" -&gt; {
            System.out.println("Shame");
        }
        case String s
        when s.equalsIgnoreCase("YES") -&gt; {
            System.out.println("You got it");
        }
        case String s
        when s.equalsIgnoreCase("NO") -&gt; {
            System.out.println("Shame");
        }
        case String s -&gt; {
            System.out.println("Sorry?");
        }
    }
}

// As of Java 21
static void exhaustiveSwitchWithBetterEnumSupport(CardClassification c) {
    switch (c) {
        case Suit.CLUBS -&gt; {
            System.out.println("It's clubs");
        }
        case Suit.DIAMONDS -&gt; {
            System.out.println("It's diamonds");
        }
        case Suit.HEARTS -&gt; {
            System.out.println("It's hearts");
        }
        case Suit.SPADES -&gt; {
            System.out.println("It's spades");
        }
        case Tarot t -&gt; {
            System.out.println("It's a tarot");
        }
    }
}

// As of Java 21
sealed interface Currency permits Coin {}
enum Coin implements Currency { HEADS, TAILS } 

static void goodEnumSwitch1(Currency c) {
    switch (c) {
        case Coin.HEADS -&gt; {    // Qualified name of enum constant as a label
            System.out.println("Heads");
        }
        case Coin.TAILS -&gt; {
            System.out.println("Tails");
        }
    }
}

static void goodEnumSwitch2(Coin c) {
    switch (c) {
        case HEADS -&gt; {
            System.out.println("Heads");
        }
        case Coin.TAILS -&gt; {    // Unnecessary qualification but allowed
            System.out.println("Tails");
        }
    }
}

// As of Java 21
static void testNew(Object obj) {
    switch (obj) {
        case String s when s.length() == 1 -&gt; ...
        case String s                      -&gt; ...
        ...
    }
}

>但是JDK21还不支持原始类型的匹配

而支持原始类型的匹配使用示例如下:

switch (x.getStatus()) {
    case 0 -&gt; "okay";
    case 1 -&gt; "warning";
    case 2 -&gt; "error";
    default -&gt; "unknown status: " + x.getStatus();
}

switch (x.getStatus()) {
    case 0 -&gt; "okay";
    case 1 -&gt; "warning";
    case 2 -&gt; "error";
    case int i -&gt; "unknown status: " + i;
}

switch (x.getYearlyFlights()) {
    case 0 -&gt; ...;
    case 1 -&gt; ...;
    case 2 -&gt; issueDiscount();
    case int i when i &gt;= 100 -&gt; issueGoldCard();
    case int i -&gt; ... appropriate action when i &gt; 2 &amp;&amp; i &lt; 100 ...
}

long v = ...;
switch (v) {
    case 1L              -&gt; ...;
    case 2L              -&gt; ...;
    case 10_000_000_000L -&gt; ...;
    case 20_000_000_000L -&gt; ...;
    case long x          -&gt; ... x ...;
}

if (roomSize instanceof byte) { // check if value of roomSize fits in a byte
    ... (byte) roomSize ... // yes, it fits! but cast is required
}

另外针对instanceof示例如下:

byte b = 42;
b instanceof int;         // true (unconditionally exact)

int i = 42;
i instanceof byte;        // true (exact)

int i = 1000;
i instanceof byte;        // false (not exact)

int i = 16_777_217;       // 2^24 + 1
i instanceof float;       // false (not exact)
i instanceof double;      // true (unconditionally exact)
i instanceof Integer;     // true (unconditionally exact)
i instanceof Number;      // true (unconditionally exact)

float f = 1000.0f;
f instanceof byte;        // false
f instanceof int;         // true (exact)
f instanceof double;      // true (unconditionally exact)

double d = 1000.0d;
d instanceof byte;        // false
d instanceof int;         // true (exact)
d instanceof float;       // true (exact)

Integer ii = 1000;
ii instanceof int;        // true (exact)
ii instanceof float;      // true (exact)
ii instanceof double;     // true (exact)

Integer ii = 16_777_217;
ii instanceof float;      // false (not exact)
ii instanceof double;     // true (exact)

JEP 508: Vector API (Tenth Incubator)

JDK16引入了JEP 338: Vector API (Incubator)提供了jdk.incubator.vector来用于矢量计算 JDK17进行改进并作为第二轮的incubatorJEP 414: Vector API (Second Incubator) JDK18的JEP 417: Vector API (Third Incubator)进行改进并作为第三轮的incubator JDK19的JEP 426:Vector API (Fourth Incubator)作为第四轮的incubator JDK20的JEP 438: Vector API (Fifth Incubator)作为第五轮的incubator JDK21的JEP 448: Vector API (Sixth Incubator)作为第六轮的incubator JDK22的JEP 460: Vector API (Seventh Incubator)作为第七轮的incubator JDK23的JEP 469: Vector API (Eighth Incubator)作为第八轮incubator JDK24的JEP 489: Vector API (Ninth Incubator)则作为第九轮incubator,与JDK23相比做了一些变动:比如引入了一个新的基于值的类Float16,用于表示IEEE 754二进制16格式的16位浮点数。

JDK25作为第十轮incubator,主要变化是:VectorShuffle现在支持访问和访问MemorySegment,该实现是通过Foreign Function & Memory API (JEP 454) 而不是通过HotSpot内部的C++代码,提高了可维护性,另外对Float16值的加法、减法、除法、乘法、平方根和fused乘法/加法运算现在支持x64 cpu自动矢量化

JEP 509: JFR CPU-Time Profiling (Experimental)

本特性引入了实验版的CPU-Time Profiling,可以捕获更准确的CPU时间分析信息 使用示例

$ java -XX:StartFlightRecording=jdk.CPUTimeSample#enabled=true,filename=profile.jfr ...
$ jfr view cpu-time-hot-methods profile.jfr

配合jcmd使用如下

jcmd <pid> JFR.start settings=/tmp/cpu_profile.jfc duration=4m
jcmd <pid> JFR.stop

JEP 510: Key Derivation Function API

JDK 21中包含的KEM API(JEP 452)是HPKE的一个组成部分,标志着Java朝着HPKE迈出的第一步,并为后量子挑战做好了准备。 在JDK24的JEP 478: Key Derivation Function API (Preview)中提出了HPKE的另一个组成部分,作为这一方向上的下一步:密钥派生函数(KDFs)的API,作为预览版本 在JDK25转为正式版,无需--enable-preview参数

使用示例如下:

// Create a KDF object for the specified algorithm
KDF hkdf = KDF.getInstance("HKDF-SHA256"); 

// Create an ExtractExpand parameter specification
AlgorithmParameterSpec params =
    HKDFParameterSpec.ofExtract()
                     .addIKM(initialKeyMaterial)
                     .addSalt(salt).thenExpand(info, 32);

// Derive a 32-byte AES key
SecretKey key = hkdf.deriveKey("AES", params);

// Additional deriveKey calls can be made with the same KDF object

JEP 511: Module Import Declarations

>与JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)类似,本特性主要是为了简化语法方便新手使用,通过新引入module的import,来一次性导入module下所有package底下的类

JDK23的JEP 476: Module Import Declarations (Preview)作为第一个preview JDK24的JEP 494: Module Import Declarations (Second Preview)作为第二次preview,与JDK23不同的是取消了模块不允许声明对java.base模块传递依赖的限制,并修订了java.se模块声明,使其传递性地依赖于java.base模块。这些变化意味着导入java.se模块将按需导入整个Java SE API。此外,现在允许按需声明的类型导入声明覆盖模块导入声明。 JDK25作为正式版,没有变化

示例:

import module java.base;  // 包含了import java.io.*; import java.util.*;

import module java.base;      // exports java.util, which has a public Date class
import module java.sql;       // exports java.sql, which has a public Date class

import java.sql.Date;         // resolve the ambiguity of the simple name Date!

...
Date d = ...                  // Ok!  Date is resolved to java.sql.Date
...

>由于是正式版,不再需要使用--enable-preview参数来开启

JEP 512: Compact Source Files and Instance Main Methods

JDK21的JEP 445: Unnamed Classes and Instance Main Methods (Preview)作为首次preview,引入了未命名的类和实例main方法特性可以简化hello world示例,方便java新手入门 JDK22的JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)作为第二次的preview JDK23的JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)作为第三次preview JDK24的JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)则作为第四次preview JDK25作为正式版本,有些改动:

  • console I/O的新IO类现在位于java.lang,而不是java.io包,现在隐式导入到每个源文件
  • IO类的静态方法不再隐式导入compact source files,需要显示导入
  • IO类的实现基于System.out及System.in,而非java.io.Console类

示例如下:

void main() {
    String name = IO.readln("Please enter your name: ");
    IO.print("Pleased to meet you, ");
    IO.println(name);
}

JEP 513: Flexible Constructor Bodies

JDK22的JEP 447: Statements before super(…) (Preview)作为第一次preview JDK23的JEP 482: Flexible Constructor Bodies (Second Preview)作为第二次preview JDK24的JEP 492: Flexible Constructor Bodies (Third Preview)作为第三次preview JDK25作为正式版本,没有变化

比如在JEP 447之前的代码如下:

public class PositiveBigInteger extends BigInteger {

    public PositiveBigInteger(long value) {
        super(value);               // Potentially unnecessary work
        if (value &lt;= 0)
            throw new IllegalArgumentException(non-positive value);
    }

}

在JEP 447之后代码可以如下:

public class PositiveBigInteger extends BigInteger {

    public PositiveBigInteger(long value) {
        if (value &lt;= 0)
            throw new IllegalArgumentException(non-positive value);
        super(value);
    }

}

JEP 514: Ahead-of-Time Command-Line Ergonomics

在JDK24的JEP 483: Ahead-of-Time Class Loading & Linking支持了通过Ahead-of-Time Cache来存储已经读取、解析、加载和链接的类 在JDK25则通过简化常见用例所需的命令来加速java应用程序的启动。

在JDK24时分两步创建AOT缓存:

  • 首先运行application来记录AOT配置:
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar com.example.App ...
  • 接着使用该配置来创建AOT缓存:
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -cp app.jar
  • 最后使用AOT缓存启动:
java -XX:AOTCache=app.aot -cp app.jar com.example.App ...

>AOT缓存将读取、解析、加载和链接(通常在程序执行期间即时完成)的任务提前到缓存创建的早期阶段。因此,在执行阶段,程序启动速度更快,因为其类可以从缓存中快速访问。其性能提升可以高达 42%。 >但是需要运行2次来创建AOT缓存。留下AOT配置文件也很不方便,它只是一个临时文件,生产运行不需要,可以删除。

JDK25通过引入AOTCacheOutput将两步合为一步,它实际上将其调用拆分为两个子调用: 第一个执行训练运行 (AOTMode=record),然后第二个创建AOT缓存 (AOTMode=create),可以通过新的环境变量JDK_AOT_VM_OPTIONS来覆盖传递给cache create这个子过程的VM命令。

java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...

>当以这种方式操作时,JVM为AOT配置创建临时文件,并在完成时删除该文件。

使用的时候一样:

java -XX:AOTCache=app.aot -cp app.jar com.example.App ...

JEP 515: Ahead-of-Time Method Profiling

在JDK24的JEP 483: Ahead-of-Time Class Loading & Linking支持了通过Ahead-of-Time Cache来存储已经读取、解析、加载和链接的类 JVM可以识别执行最频繁或消耗最多CPU时间的代码,并通过将其编译为本机代码来优化此代码。此过程称为分析。简单来说,配置文件是与方法相关的有用信息的集合,例如已执行的次数。当应用程序以通常的方式 (没有AOT缓存) 运行时,这些配置文件在应用程序执行开始时收集。这个JEP背后的概念是,我们可以在训练运行期间收集配置文件,然后在后续运行中重复使用它们。这意味着在以后的执行中,无需在启动后收集配置文件,从而可以立即开始代码编译。训练运行的质量会显着影响应用程序预热时间的改善。训练跑得越好,在随后的跑中获得的性能增强就越大。 本特性将生产环境做的Method Profiling挪到了Ahead-of-Time Cache阶段,使得生产环境启动的时候就读取这些数据,JIT立即对真正的热点方法进行编译,无需边跑边收集。

JEP 518: JFR Cooperative Sampling

本特性提高JFR异步采样Java线程堆栈时的稳定性,通过仅在安全点处遍历调用堆栈来实现此目的,同时最大程度地减少安全点偏差。

JEP 519: Compact Object Headers

在JDK24的JEP 450: Compact Object Headers (Experimental)特性中,在64位架构上,将 HotSpot JVM中的对象标头大小从96到128位减少到64位。在SPECjbb2015的测试中减少了22%的堆空间和8%的CPU时间,完成的垃圾收集数量为减少15%,一个高度并行的JSON解析器基准运行时间减少10%。 在JDK25转为正式版,无需-XX:+UnlockExperimentalVMOptions命令

-XX:+UseCompactObjectHeaders

JEP 520: JFR Method Timing & Tracing

本特性引入了两个新的JFR事件,jdk.MethodTiming和jdk.MethodTrace,通过字节码织入来追踪方法 使用示例

$ java -XX:StartFlightRecording:jdk.MethodTrace#filter=java.util.HashMap::resize,filename=recording.jfr ...
$ jfr print --events jdk.MethodTrace --stack-depth 20 recording.jfr
jdk.MethodTrace {
    startTime = 00:39:26.379 (2025-03-05)
    duration = 0.00113 ms
    method = java.util.HashMap.resize()
    eventThread = "main" (javaThreadId = 3)
    stackTrace = [
      java.util.HashMap.putVal(int, Object, Object, boolean, boolean) line: 636
      java.util.HashMap.put(Object, Object) line: 619
      sun.awt.AppContext.put(Object, Object) line: 598
      sun.awt.AppContext.<init>(ThreadGroup) line: 240
      sun.awt.SunToolkit.createNewAppContext(ThreadGroup) line: 282
      sun.awt.AppContext.initMainAppContext() line: 260
      sun.awt.AppContext.getAppContext() line: 295
      sun.awt.SunToolkit.getSystemEventQueueImplPP() line: 1024
      sun.awt.SunToolkit.getSystemEventQueueImpl() line: 1019
      java.awt.Toolkit.getEventQueue() line: 1375
      java.awt.EventQueue.invokeLater(Runnable) line: 1257
      javax.swing.SwingUtilities.invokeLater(Runnable) line: 1415
      java2d.J2Ddemo.main(String[]) line: 674
    ]
}

JEP 521: Generational Shenandoah

在JDK24的JEP 404: Generational Shenandoah (Experimental)提供了一个实验性的分代模式,与其他分代收集器一样分为年轻代和年老代 在JDK25转为正式版本,不再需要-XX:+UnlockExperimentalVMOptions命令

-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational

细项解读

上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 25 Release Notes,这里举几个例子。

添加项

  • Support for reading all remaining characters from a Reader (JDK-8354724) >java.io.Reader新增了方法readAllAsString可以读取剩余字符到String,新增readAllLines读取剩余字符到List<string>

  • New connectionLabel Method in java.net.http.HttpResponse to Identify Connections (JDK-8350279) >对HttpResponse新增了connectionLabel方法用于关联connection

  • New Property to Construct ZIP FileSystem as Read-only (JDK-8350880) >新增readOnly支持FileSystems.newFileSystem(pathToZipFile, Map.of(“accessMode”,”readOnly”))

  • Updates to ForkJoinPool and CompletableFuture (JDK-8319447) >ForkJoinPool做了更新以实现ScheduledExecutorService,新增了submitWithTimeout方法支持timeout参数

  • Thread Dumps Generated by HotSpotDiagnosticMXBean.dumpThreads and jcmd Thread.dump_to_file Updated to Include Lock Information (JDK-8356870) >com.sun.management.HotSpotDiagnosticMXBean.dumpThreads以及jcmd Thread.dump_to_file生成的线程堆栈现在包含了锁信息

  • G1 Reduces Remembered Set Overhead by Grouping Regions into Shared Card Sets (JDK-8343782) >以前每个Region都维护自己的G1CardSet,导致内存占用高,新设计在 Remark 阶段之后,把预计会一起被清空的Region归为一组,并分配同一个共享的G1CardSet,省去了它们之间逐一跟踪引用的开销。

移除项

  • java.net.Socket Constructors Can No Longer Be Used to Create a Datagram Socket (JDK-8356154) >java.net.Socket废弃了两个构造器,不再支持创建datagram sockets,需要改为java.net.DatagramSocket替代

  • Removal of PerfData Sampling (JDK-8241678) >-XX:PerfDataSamplingInterval这个被移除了

废弃项

  • Deprecate the Use of java.locale.useOldISOCodes System Property (JDK-8353118) >java.locale.useOldISOCodes这个属性被废弃了

  • The UseCompressedClassPointers Option is Deprecated (JDK-8350753) >UseCompressedClassPointers这个参数被废弃了,接下来将默认开启压缩类指针

  • Various Permission Classes Deprecated for Removal (JDK-8348967, JDK-8353641, JDK-8353642, JDK-8353856, JDK-8347985, JDK-8351224, JDK-8351310) 以下这些Permission相关的类被标记废弃

java.security.UnresolvedPermission
javax.net.ssl.SSLPermission
javax.security.auth.AuthPermission
javax.security.auth.PrivateCredentialPermission
javax.security.auth.kerberos.DelegationPermission
javax.security.auth.kerberos.ServicePermission
com.sun.security.jgss.InquireSecContextPermission
java.lang.RuntimePermission
java.lang.reflect.ReflectPermission
java.io.FilePermission
java.io.SerializablePermission
java.nio.file.LinkPermission
java.util.logging.LoggingPermission
java.util.PropertyPermission
jdk.jfr.FlightRecorderPermission
java.net.NetPermission
java.net.URLPermission
jdk.net.NetworkPermission
com.sun.tools.attach.AttachPermission
com.sun.jdi.JDIPermission
java.lang.management.ManagementPermission
javax.management.MBeanPermission
javax.management.MBeanTrustPermission
javax.management.MBeanServerPermission
javax.management.remote.SubjectDelegationPermission

已知问题修复

  • ZGC Now Avoids String Deduplication for Short-Lived Strings (JDK-8347337) >ZGC将避免对一些生命周期短的String进行Deduplication,避免不必要的开销

  • G1 Reduces Pause Time Spikes by Improving Region Selection (JDK-8351405) >G1在Mixed GC的时候会引起pause time飙升,此次通过region选择进行了优化

  • No More OutOfMemoryErrors Due to JNI in Serial/Parallel GC (JDK-8192647) >修复了Serial/Parallel GC因为JNI导致的OOM

已知问题

  • Regression in Serialization of LocalDate Class Objects (JDK-8367031) 在 java.time 包中,若干类的序列化 Class 对象在 JDK 25 与早期版本之间不再兼容。受影响的具体类包括:LocalDate、YearMonth、MonthDay、HijrahDate 兼容性规则:如果把上述某个类的Class对象在早期版本序列化,再到 JDK 25 反序列化,或者反向操作,都会抛出 InvalidClassException,例如writeObject(LocalDate.class) 但如果是序列化实例,则不受影响writeObject(LocalDate.now())

  • Performance Regression in java.lang.ClassValue::get (JDK-8358535) 在 JDK 25 中,为了增强 ClassValue 在各种并发场景下的健壮性,JDK-8351996 对其进行了更新。 然而,这次改动导致:在调用 ClassValue.remove 之后,ClassValue.get 的执行速度明显变慢。

    • 大多数应用不会直接使用 ClassValue,因此不会感知到这一退化。
    • 但若某个库同时调用 ClassValue.get 与 remove(例如 Scala 2.12 的标准库),就可能受到性能影响。 该性能回退已在 JDK-8358535 中被修复。
  • -XX:+UseTransparentHugePages Fails to Enable Huge Pages for G1 (JDK-8366434) 在把Transparent Huge Pages(THP)模式设置为 madvise 的系统上, 即使启动参数里加了 -XX:+UseTransparentHugePages,默认垃圾回收器 G1 也不会实际启用大页。临时解决办法:把 THP 模式改成 always,即可让 G1 正常使用Transparent Huge Pages:

未经允许不得转载:紫竹林-程序员中文网 » Java25的新特性

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
关于我们 免责申明 意见反馈 隐私政策
程序员中文网:公益在线网站,帮助学习者快速成长!
关注微信 技术交流
推荐文章
每天精选资源文章推送
推荐文章
随时随地碎片化学习
推荐文章
发现有趣的